#ifndef NTUPLE_H
#define NTUPLE_H
#include <stdexcept>
namespace util{
	/** Template for a tuple of all-equal objects*/
	template<typename T, int size>
		class NTuple
		{
			protected:
				/**Elements in the tuple */
				T v[size];
			public:
				/** Read only reference to an element in the tuple */
				const T& operator[](int pos) const {return v[pos];}
				/** Read-write reference to an element in the tuple */
				T& operator[](int pos) {return v[pos];}

				/** Gets the element at the given position (read only), but throws if index is out of the tuple range */
				const T& at(int pos) const{ if(pos <0 || pos > size) throw std::out_of_range(); return v[pos];}
				/** Gets the element at the given position (read write), but throws if index is out of the tuple range */
                T& at(int pos){ if(pos <0 || pos > size) throw std::out_of_range("Tuple param out of range"); return v[pos];}
		};

	/** Tuple of 2 elements */
	template <typename T> class Pair : public NTuple<T,2>{
		public:
			Pair(){}
			Pair(const T &t1, const T &t2)
			{
				(*this)[0] = t1;
				(*this)[1] = t2;
			}
	};

	/** Tuple of 3 elements */
	template <typename T> class Triplet : public NTuple<T,3>{
		public:
			/** Default constructor */
			Triplet(){}
			/** Constructor that creates a triplet from three values */
			Triplet(const T&t1, const T&t2, const T&t3)
			{
				(*this)[0] = t1;
				(*this)[1] = t2;
				(*this)[2] = t3;
			}
			/** Copy constructor from a 3 objects NTuple */
			Triplet(const NTuple<T,3>& t)
			{
				for(int i=0;i<3;i++)
					(*this)[i] = t[i]; 
			}
	};
}

#endif
